package ai.people.core.plugin.utils;

import ai.people.core.plugin.annotation.HotRefresh;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.cloud.util.ProxyUtils;

import java.lang.reflect.Field;

/**
 * @author yuanqinglong
 * @date 2022/6/13 19:09
 */
public class ManualRegisterBeanUtil {


    private final static Logger logger = LoggerFactory.getLogger(ManualRegisterBeanUtil.class);

    /**
     * 注册bean
     *
     * @param clazz       c
     * @param beanFactory bean工厂
     */
    public static void registerBean(Class<?> clazz, ConfigurableListableBeanFactory beanFactory) {
        if (HotDeployUtils.isSpringBeanClass(clazz)) {
            String beanName = HotDeployUtils.getCustomBeanName(clazz);
            BeanDefinitionRegistry registry = (BeanDefinitionRegistry) beanFactory;
            if (beanFactory.containsBeanDefinition(beanName)) {
                registry.removeBeanDefinition(beanName);
            }
            BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(clazz);
            BeanDefinition beanDefinition = builder.getBeanDefinition();
            beanDefinition.setScope("singleton");
            registry.registerBeanDefinition(beanName, beanDefinition);
            logger.info("动态注册Bean: {}", beanFactory.getBean(clazz).getClass().getSimpleName());
        }
    }

    /**
     * 热刷新bean字段
     *
     * @param beanFactory bean工厂
     */
    public static void hotRefreshBeanField(ConfigurableListableBeanFactory beanFactory) {
        String[] beanNames = BeanFactoryUtils.beanNamesForAnnotationIncludingAncestors(beanFactory, HotRefresh.class);
        DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) beanFactory;
        for (String beanName : beanNames) {
            Object bean = beanFactory.getBean(beanName);
            // 如果是代理Bean 获取原始的Bean
            if (AopUtils.isAopProxy(bean)) {
                bean = ProxyUtils.getTargetObject(bean);
            }
            for (Field field : bean.getClass().getDeclaredFields()) {
                if (field.isAnnotationPresent(HotRefresh.class)) {
                    DependencyDescriptor desc = new DependencyDescriptor(field, false);
                    // 对Bean重新进行依赖注入
                    Object dependency = defaultListableBeanFactory.resolveDependency(desc, beanName);
                    field.setAccessible(true);
                    try {
                        // 反射注入赋值
                        field.set(bean, dependency);
                        logger.info("Bean:{} 属性重新注入:{}", beanName, dependency);
                    } catch (IllegalAccessException e) {
                        logger.error("热加载注入失败", e);
                    }
                }
            }
        }
    }
}
